#include <stdio.h>
#include <iostream>
#include "Wall.h"
#include "BlockMoveAbilityVisitor.h"
#include "Board.h"
#include "Robot.h"
#include "Spinner.h"
#include "Pusher.h"
#include "Laser.h"
#include "Checkpoint.h"
#include "Repairpoint.h"
#include "Treadmill.h"
#include "Pitfall.h"
#include "MoveStepCalculator.h"
#include "MoveAbilityVisitor.h"
#include "SpinnerStepCalculator.h"
#include "ActivateAbilityVisitor.h"

using namespace std;

void ActivateFactory(std::list<GameObject*>& obbies, Board& board)
{
	std::list<GameObject*>::iterator it;

	for(it = obbies.begin(); it != obbies.end(); ++it)
	{
		ActivateAbilityVisitor activateVisitor;
		GameObject* object = (*it);

		object->Accept(activateVisitor);

		if (activateVisitor.FoundAbility())
		{
			Activatable* activatable = activateVisitor.ActivatableInterface();
			StepCalculator* calculator = activatable->GetActivationBehavior();

			calculator->GenerateSteps(board);
			calculator->Execute();
		}
	}
}

int main()
{
	Board board;
	Wall wall1, wall2;
	Robot robot1, robot2, robot3;
	Spinner spinner1;
	Pusher pusher1, pusher2;
	Laser laser1;
	Checkpoint checkpoint1;
	Repairpoint repairpoint1;
	Treadmill treadmill1;
	Pitfall pitfall1;

	spinner1.SetSpinDirection(Direction::EAST);
	pusher1.SetPushDirection(Direction::SOUTH);
	laser1.SetShootDirection(Direction::SOUTH);
	pusher2.SetPushDirection(Direction::WEST);
	treadmill1.SetPushDirection(Direction::EAST);

	wall1.SetDirection(Direction::WEST);
	wall2.SetDirection(Direction::NORTH);


	std::list<GameObject*> obbies;

	obbies.push_back(&wall1);
	obbies.push_back(&wall2);
	obbies.push_back(&robot1);
	obbies.push_back(&robot2);
	obbies.push_back(&robot3);
	obbies.push_back(&spinner1);
	obbies.push_back(&pusher1);
	obbies.push_back(&laser1);
	obbies.push_back(&checkpoint1);
	obbies.push_back(&repairpoint1);
	obbies.push_back(&pusher2);
	obbies.push_back(&treadmill1);
	obbies.push_back(&pitfall1);


	robot1.SetTest("1");
	robot1.MoveTo(1, 0);
	robot2.SetTest("2");
	robot2.MoveTo(2, 0);
	robot3.SetTest("3");
	robot3.MoveTo(3, 0);

	spinner1.MoveTo(2, 2);
	pusher1.MoveTo(5, 0);
	laser1.MoveTo(4, 1);
	wall1.MoveTo(0,0);
	wall2.MoveTo(4,4);
	checkpoint1.MoveTo(5, 3);
	repairpoint1.MoveTo(1,2);
	pusher2.MoveTo(0,4);
	treadmill1.MoveTo(2,1);
	pitfall1.MoveTo(1, 4);


	board.Resize(6, 6);

	board.Update(&wall1);
	board.Update(&wall2);
	board.Update(&robot1);
	board.Update(&robot2);
	board.Update(&robot3);
	board.Update(&spinner1);
	board.Update(&pusher1);
	board.Update(&laser1);
	board.Update(&checkpoint1);
	board.Update(&repairpoint1);
	board.Update(&pusher2);
	board.Update(&treadmill1);
	board.Update(&pitfall1);


	//board.Print();

//	BlockMoveAbilityVisitor visitor;

//	wall.Accept(visitor);
/*
	MoveAbilityVisitor visitor;
	robot1.Accept(visitor);

	if (visitor.FoundAbility())
	{
		visitor.MovableInterface()->MoveDown();
		board.Update(&robot1);

		board.Print();
	}
*/
/*
	MoveStepCalculator calculator;

	calculator.SetInitialObject(&robot3, Direction::WEST);
	calculator.GenerateSteps(board);
	calculator.Execute();

	board.Print();
*/


	char dir;
	GameObject* robot = &robot1;


	while(true)
	{ 
		std::cout << "u(p), l(eft), r(ight), d(down), q(uit), 1 2 3 (robot choice)" << std::endl;
		board.Print();
    
		std::cin >> dir;
		switch(dir)
		{
		case 'u':
			{
			MoveStepCalculator calculator;
			calculator.SetInitialObject(robot, Direction::NORTH);
			calculator.GenerateSteps(board);
			calculator.Execute();
			}
			break;
		case 'd':
			{
			MoveStepCalculator calculator;
			calculator.SetInitialObject(robot, Direction::SOUTH);
			calculator.GenerateSteps(board);
			calculator.Execute();
			}
			break;
		case 'l':
			{
			MoveStepCalculator calculator;
			calculator.SetInitialObject(robot, Direction::WEST);
			calculator.GenerateSteps(board);
			calculator.Execute();
			}
			break;
		case 'r':
			{
			MoveStepCalculator calculator;
			calculator.SetInitialObject(robot, Direction::EAST);
			calculator.GenerateSteps(board);
			calculator.Execute();
			}
			break;
		case '1':
			robot = &robot1;
			break;
		case '2':
			robot = &robot2;
			break;
		case '3':
			robot = &robot3;
			break;
		case 'q':
				return 0;
		default:
			break;
		}

		ActivateFactory(obbies, board);
	}
	return 0;
}

